home *** CD-ROM | disk | FTP | other *** search
- /*
- IsNan.c
-
- Fast, portable routines to check for IEEE transfinite numbers: INF and NAN. You
- should also look at the macro IsFinite() in VideoToolbox.h.
-
- Apple's new header file fp.h defines the macros isfinite(x) and isnan(x), and
- the function nan("255"). At present the function nan() is only implemented for
- the PowerPC, but presumably Apple will soon extend support to include the 680x0
- machines too. Surprisingly, fp.h doesn't include any equivalent to IsInf(). You
- could write something like fpclassify(x)==FP_INFINITE, but getting the sign
- would take another step.
-
- IsNan and IsInf take a shortcut in distinguishing NaN from INF. The definition
- of a NaN in the Apple Numerics book only says that a NaN is distinguished from
- an INF by having a nonzero mantissa. Unfortunately, a strict test of this
- requires testing the whole mantissa, up to 8 bytes, and in fact the routines in
- Plaugher's The Standard C Library do exactly this. (The IEEE standard ought to
- have disallowed a NaN code of zero.) We take a hybrid approach, on 680x0
- machines (i.e. 10 & 12 byte doubles) my experience is that the NaN code is
- always nonzero, unless someone goes out of their way to create a zero-code NaN,
- and what's more, in all NaNs the top bit of the mantissa is set. So it is
- sufficient to test the top bit and the code byte to distinguish between NaN and INF.
- On the other hand, the PowerPC Numerics manual says that the PowerPC chip always
- returns a NaN code of zero (seems a foolish choice), so we play safe and test
- the whole mantissa when we're dealing with 8 byte doubles.
-
- The Numerical Extensions to C group has proposed in their draft standard that
- routines very similar to these become a part of Standard C. Anyone interested in
- writing such routines should read: Plauger, P. J. (1992) The Standard C Library.
- Englewood Cliffs, NJ: Prentice Hall.
-
- PORTABILITY: Standard C. Should work on Motorola and Intel processors, but has
- only been tested on 680x0 and PowerPC processors in Macintosh computers.
-
- HISTORY:
- 8/24/91 dgp made compatible with THINK C 5.0.
- 12/23/91 dgp I replaced the #if statements by ordinary if statements, which are
- more readable and are allowed to use the sizeof() operator.
- Note that most of the if statements will be evaluated and removed by the
- compiler, with no runtime penalty.
- 12/23/91 dgp Wrote my own code to replace the SANE code since it's too slow.
- This makes IsNan() about 5 times faster.
- My code is based on the Apple Numerics Manual, 2nd edition. It says that
- a number is a NAN iff the exponent is all ones and the fraction is nonzero.
- I make a slight shortcut in checking only the top 15 bits of the fraction,
- since that includes the byte that specifies the NAN type, on the premise
- that all NANs that I will actually see in practice will have nonzero type.
- My code handles the ordinary cases of 10 or 12 byte doubles. The weird
- case of shorter doubles (which are unlikely since they run very slowly)
- are detected by the assert() test at the beginning.
- 12/23/91 dgp Asked the THINK C compiler not to time this routine.
- 12/29/91 dgp Eliminated the need for SANE.h and Types.h. The SANE stuff
- now appears in its own file: SANE.c.
- Wrote IsInf().
- Wrote a new macro definition, in VideoToolbox.h, for IsFinite(),
- that allows fast inline testing for whether a number is ok, i.e. neither
- NAN nor INF.
- 1/14/92 dgp Changed IsNan() to now return the type (1..255) of the NAN, or zero
- if not a NAN. This will break programs that assume the true value is always 1,
- e.g. nans+=IsNan(a);
- Fixed IsInf() to correctly return sign of ±INF.
- 1/18/92 dgp Rewrote routines, making them simpler, and always checking the most
- significant bit of the mantissa in testing for NAN.
- 6/5/93 dgp Updated documentation.
- 7/31/94 dgp added support for 8-byte doubles, to support the PowerPC.
- */
-
- #include "VideoToolbox.h"
- #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
- #pragma options(!profile) /* THINK C: attribute to the caller the time spent here. */
- #endif
- #define EXPONENT 0
- #define MANTISSA ((sizeof(double)-8)/2)
- int IsNan(double x);
- int IsInf(double x);
- #define zeroCode 21 /* NaN with zero code */
-
- int IsNan(double x)
- /* Returns x's NAN type (1...255) or zero if x is not a NAN. */
- /* If NaN type is zero, return zeroCode. */
- {
- register short i;
- register unsigned long j;
-
- switch(sizeof(double)){
- case 8:
- j=((unsigned long *)&x)[0];
- if((j & 0x7FF00000)==0x7FF00000){ /* either NAN or INF */
- j&=0xFFFFF; /* mantissa */
- if(j==0 && ((unsigned long *)&x)[1]==0)return 0; /* INF */
- i=j>>5;
- }else return 0;
- break;
- case 10:
- case 12:
- if((((short *)&x)[EXPONENT] & 0x7FFF)==0x7FFF){ /* either NAN or INF */
- i=((short *)&x)[MANTISSA] & 0x7FFF;
- if(i==0)return 0;
- }else return 0;
- break;
- default:
- PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
- ,__FILE__,__LINE__,sizeof(double));
- }
- i&=0xFF;
- if(i==0)i=zeroCode;
- return i;
- }
-
- int IsInf(double x)
- /* Returns -1 for -INF, 0 for not INF, and +1 for +INF. */
- {
- register short i;
- register long j;
-
- switch(sizeof(double)){
- case 8:
- j=((long *)&x)[0];
- if((j & 0x7FF00000)==0x7FF00000){ /* either NAN or INF */
- if(j&0xFFFFF==0 && ((long *)&x)[1]==0){
- if(j<0)return -1; /* -INF */
- else return 1; /* +INF */
- }
- }
- break;
- case 10:
- case 12:
- i=((short *)&x)[EXPONENT];
- if((i & 0x7FFF)==0x7FFF){ /* either NAN or INF */
- if((((short *)&x)[MANTISSA] & 0x7FFF)==0){
- if(i<0)return -1; /* -INF */
- else return 1; /* +INF */
- }
- }
- break;
- default:
- PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
- ,__FILE__,__LINE__,sizeof(double));
- }
- return 0;
- }
-